//--------------------------------------------------------------------------------
// This file is part of the Windows Workflow Foundation Sample Code
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This source code is intended only as a supplement to Microsoft
// Development Tools and/or on-line documentation.  See these other
// materials for detailed information regarding Microsoft code samples.
// 
// THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//--------------------------------------------------------------------------------

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Activities;
using System.Drawing;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reflection;
using System.Security.Principal;
using System.Configuration;
using System.Web;

namespace Microsoft.Samples.Workflow.UI
{
    static class Helpers
    {
        internal static Bookmark GetBookmark(Activity activity)
        {
            Bookmark bookmark = null;
            if (activity is InteractionBaseActivity)
            {
                bookmark = new Bookmark(activity.QualifiedName, ((InteractionBaseActivity)activity).InteractionId);
            }
            else if (activity is CompositeActivity)
            {
                // We only support one interaction activity per child of navigator.  So find the first one
                // and break.
                Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
                compositeActivities.Enqueue(activity as CompositeActivity);
                while (compositeActivities.Count > 0)
                {
                    CompositeActivity compositeActivity = compositeActivities.Dequeue();
                    foreach (Activity child in compositeActivity.EnabledActivities)
                    {
                        if (child is InteractionBaseActivity)
                        {
                            bookmark = new Bookmark(child.QualifiedName, ((InteractionBaseActivity)child).InteractionId);
                            break;
                        }

                        if (child is CompositeActivity)
                        {
                            compositeActivities.Enqueue(child as CompositeActivity);
                        }
                    }
                }
            }

            return bookmark;
        }

        internal static ReadOnlyCollection<Bookmark> GetHistoryBookmarks(ReadOnlyCollection<Activity> history)
        {
            List<Bookmark> bookmarks = new List<Bookmark>();
            foreach (Activity activity in history)
            {
                bookmarks.Add(GetBookmark(activity));
            }

            return bookmarks.AsReadOnly();
        }

        internal static InteractionContext GetContext(Bookmark bookmark, Activity activity, ActivityExecutionStatus statusFilter)
        {
            InteractionContext interaction = null;
            if (activity is InteractionBaseActivity && activity.ExecutionStatus == statusFilter)
            {
                InteractionContext context = ((InteractionBaseActivity)activity).GetInteractionContext();
                if (bookmark == null || bookmark.InteractionId == context.Bookmark.InteractionId)
                {
                    interaction = context;
                }
            }
            else if (activity is CompositeActivity)
            {
                // We only support one interaction activity per child of navigator.  So find the first one
                // and break.
                Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
                compositeActivities.Enqueue(activity as CompositeActivity);
                while (compositeActivities.Count > 0)
                {
                    CompositeActivity compositeActivity = compositeActivities.Dequeue();
                    foreach (Activity child in compositeActivity.EnabledActivities)
                    {
                        if (child is InteractionBaseActivity && activity.ExecutionStatus == statusFilter)
                        {
                            InteractionContext context = null;
                            if (activity is Navigator && ((Navigator)activity).Current != null)
                            {
                                context = GetInteractionContextForNavigator(activity as Navigator);
                            }
                            else
                            {
                                context = ((InteractionBaseActivity)child).GetInteractionContext();
                            }
                            if (bookmark == null || bookmark.InteractionId == context.Bookmark.InteractionId)
                            {
                                interaction = context;
                                break;
                            }
                        }

                        if (child is CompositeActivity)
                        {
                            compositeActivities.Enqueue(child as CompositeActivity);
                        }
                    }
                }
            }

            return interaction;
        }

        internal static InteractionContext GetContext(Bookmark bookmark, ReadOnlyCollection<Activity> history)
        {
            InteractionContext interaction = null;
            foreach (Activity activity in history)
            {
                interaction = GetContext(bookmark, activity, ActivityExecutionStatus.Closed);
                if (interaction != null)
                {
                    break;
                }
            }

            return interaction;
        }

        //internal static ReadOnlyCollection<InteractionContext> GetPastContexts(ReadOnlyCollection<Activity> history)
        //{
        //    List<InteractionContext> pastContexts = new List<InteractionContext>();
        //    for (int i = 0; i < history.Count; i++)
        //    {
        //        Activity activity = history[i];
        //        if (activity is InteractionBaseActivity)
        //        {
        //            InteractionContext context = ((InteractionBaseActivity)activity).GetInteractionContext();
        //            pastContexts.Add(context);
        //        }
        //        else if (activity is CompositeActivity)
        //        {
        //            // We only support one interaction activity per child of navigator.  So find the first one
        //            // and break.
        //            Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
        //            compositeActivities.Enqueue(activity as CompositeActivity);
        //            while (compositeActivities.Count > 0)
        //            {
        //                CompositeActivity compositeActivity = compositeActivities.Dequeue();
        //                foreach (Activity child in compositeActivity.EnabledActivities)
        //                {
        //                    if (child is InteractionBaseActivity && child.ExecutionStatus == ActivityExecutionStatus.Closed)
        //                    {
        //                        pastContexts.Add(((InteractionBaseActivity)child).GetInteractionContext());
        //                        break;
        //                    }

        //                    if (child is CompositeActivity)
        //                        compositeActivities.Enqueue(child as CompositeActivity);
        //                }
        //            }
        //        }
        //    }

        //    return pastContexts.AsReadOnly();
        //}

        internal static List<InteractionContext> GetActiveChildContexts(InteractionGroupActivity interactionGroup)
        {
            List<InteractionContext> pageContexts = new List<InteractionContext>();
            if (interactionGroup == null)
            {
                return pageContexts;
            }

            // First check the activities running in the same context.
            foreach (Activity child in interactionGroup.EnabledActivities)
            {
                if (child is InteractionActivity && child.ExecutionStatus == ActivityExecutionStatus.Executing)
                {
                    pageContexts.Add(((InteractionActivity)child).GetInteractionContext());
                }
                else if (child is Navigator)
                {
                    InteractionContext context = GetInteractionContextForNavigator((Navigator)child);
                    if (context != null)
                    {
                        pageContexts.Add(context);
                    }
                }
            }
            return pageContexts;
        }

        internal static InteractionContext GetInteractionContextForNavigator(Navigator navigator)
        {
            InteractionBaseActivity interactionActivity = navigator.Current as InteractionBaseActivity;
            if (interactionActivity != null)
            {
                return interactionActivity.GetInteractionContext();
            }

            return null;
        }

        internal static List<InteractionContext> GetAvailableChildContexts(InteractionGroupActivity interactionGroup)
        {
            List<InteractionContext> pageContexts = new List<InteractionContext>();
            if (interactionGroup == null)
            {
                return pageContexts;
            }

            foreach (Activity child in interactionGroup.EnabledActivities)
            {
                if (child is InteractionActivity &&
                    (child.ExecutionStatus == ActivityExecutionStatus.Initialized || child.ExecutionStatus == ActivityExecutionStatus.Executing))
                {
                    pageContexts.Add(((InteractionActivity)child).GetInteractionContext());
                }
                else
                {
                    Navigator navigator = child as Navigator;
                    if (navigator != null)
                    {
                        Activity startActivity = GetImmediateChildByName(navigator, navigator.StartWith);
                        if (startActivity is InteractionBaseActivity)
                        {
                            if (child.ExecutionStatus == ActivityExecutionStatus.Initialized ||
                                child.ExecutionStatus == ActivityExecutionStatus.Executing)
                            {
                                pageContexts.Add(((InteractionBaseActivity)startActivity).GetInteractionContext());
                            }
                        }
                    }
                }
            }
            return pageContexts;
        }

        internal static List<InteractionContext> GetAllChildContexts(Activity current, bool activeOnly)
        {
            List<InteractionContext> pageContexts = new List<InteractionContext>();
            CompositeActivity activity = current as CompositeActivity;
            if (activity == null)
            {
                return pageContexts;
            }

            // First check the activities running in the same context.
            Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
            compositeActivities.Enqueue(activity);
            while (compositeActivities.Count > 0)
            {
                CompositeActivity compositeActivity = compositeActivities.Dequeue();
                foreach (Activity child in compositeActivity.EnabledActivities)
                {
                    if (child is InteractionBaseActivity)
                    {
                        if ((activeOnly && child.ExecutionStatus == ActivityExecutionStatus.Executing) ||
                            (!activeOnly && (child.ExecutionStatus == ActivityExecutionStatus.Executing || child.ExecutionStatus == ActivityExecutionStatus.Initialized)))
                        {
                            pageContexts.Add(((InteractionBaseActivity)child).GetInteractionContext());
                        }
                    }

                    if (child is CompositeActivity)
                    {
                        compositeActivities.Enqueue(child as CompositeActivity);
                    }
                }
            }
            return pageContexts;
        }

        internal static InteractionContext GetChildContext(Activity current)
        {
            CompositeActivity activity = current as CompositeActivity;
            if (activity == null)
            {
                return null;
            }

            Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
            compositeActivities.Enqueue(activity);
            while (compositeActivities.Count > 0)
            {
                CompositeActivity compositeActivity = compositeActivities.Dequeue();
                foreach (Activity child in compositeActivity.EnabledActivities)
                {
                    if (child is InteractionActivity && child.ExecutionStatus == ActivityExecutionStatus.Executing)
                    {
                        return ((InteractionBaseActivity)child).GetInteractionContext();
                    }

                    if (child is CompositeActivity)
                    {
                        compositeActivities.Enqueue(child as CompositeActivity);
                    }
                }
            }

            return null;
        }

        internal static List<Activity> GetAllChildActivities(Activity activity)
        {
            List<Activity> activities = new List<Activity>();
            CompositeActivity compositeActivity = activity as CompositeActivity;
            if (compositeActivity == null)
            {
                return activities;
            }

            Queue<CompositeActivity> compositeActivities = new Queue<CompositeActivity>();
            compositeActivities.Enqueue(compositeActivity);
            while (compositeActivities.Count > 0)
            {
                compositeActivity = compositeActivities.Dequeue();
                foreach (Activity child in compositeActivity.EnabledActivities)
                {
                    activities.Add(child);

                    if (child is CompositeActivity)
                    {
                        compositeActivities.Enqueue(child as CompositeActivity);
                    }
                }
            }

            return activities;
        }

        internal static Activity GetImmediateChildByName(Activity parent, string childName)
        {
            Activity activity = null;
            CompositeActivity compositeActivity = parent as CompositeActivity;
            if (compositeActivity != null)
            {
                foreach (Activity child in compositeActivity.EnabledActivities)
                {
                    if (child.QualifiedName == childName)
                    {
                        activity = child;
                        break;
                    }
                }
            }

            return activity;
        }

        internal static Activity GetRootActivity(Activity activity)
        {
            if (activity == null)
            {
                throw new ArgumentNullException("activity");
            }

            while (activity.Parent != null)
            {
                activity = activity.Parent;
            }

            return activity;
        }

        internal static CompositeActivity GetDeclaringActivity(Activity activity)
        {
            if (activity == null)
            {
                throw new ArgumentNullException("activity");
            }

            CompositeActivity parent = activity.Parent;
            while (parent != null)
            {
                // This will be the root
                if (parent.Parent == null)
                    return parent;

                // Any custom activity found is the declaring activity
                if (IsCustomActivity(parent))
                {
                    return parent;
                }

                parent = parent.Parent;
            }
            return null;
        }

        internal static bool IsCustomActivity(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
            {
                throw new ArgumentNullException("compositeActivity");
            }

            if (compositeActivity.UserData.Contains(UserDataKeys.CustomActivity))
            {
                return (bool)(compositeActivity.UserData[UserDataKeys.CustomActivity]);
            }
            else
            {
                try
                {
                    CompositeActivity activity = Activator.CreateInstance(compositeActivity.GetType()) as CompositeActivity;
                    if (activity != null && activity.Activities.Count > 0)
                    {
                        compositeActivity.UserData[UserDataKeys.CustomActivityDefaultName] = activity.Name;
                        compositeActivity.UserData[UserDataKeys.CustomActivity] = true;//TODO: Akash, is it needed?
                        return true;
                    }
                }
                catch
                {
                    // TODO: handle exceptions
                }
            }

            compositeActivity.UserData[UserDataKeys.CustomActivity] = false;//TODO: Akash, is it needed?
            return false;
        }

        internal static bool IsOOBEventTypeActivity(Type activityType)
        {
            if (typeof(IEventActivity).IsAssignableFrom(activityType) || 
                typeof(EventDrivenActivity).IsAssignableFrom(activityType) || 
                typeof(ListenActivity).IsAssignableFrom(activityType))
            {
                return true;
            }

            return false;
        }

        internal static bool IsOOBStateMachineActivity(Type activityType)
        {
            if (typeof(StateActivity).IsAssignableFrom(activityType) || 
                typeof(StateInitializationActivity).IsAssignableFrom(activityType) ||
                typeof(StateFinalizationActivity).IsAssignableFrom(activityType) ||
                typeof(SetStateActivity).IsAssignableFrom(activityType))
            {
                return true;
            }

            return false;
        }

        internal static bool IsOOBWebServiceActivity(Type activityType)
        {
            if (typeof(WebServiceInputActivity).IsAssignableFrom(activityType) ||
                typeof(WebServiceOutputActivity).IsAssignableFrom(activityType) ||
                typeof(WebServiceFaultActivity).IsAssignableFrom(activityType))
            {
                return true;
            }

            return false;
        }
    }
}
